home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*_______________________________________________________________________
- |
- | blixserver.c - server side of the world highscore for blix
- |
- |
- | this is one program that needs to run on a server. It is
- | not a bullet proof program in the sense that it produces
- | nice warningmessages when you install it wrong, nor does
- | it produce any logging of the access done to this server.
- |
- | to install make a user with name blix;
- | o compile the serverprogram with
- | cc -O -o blixserver blixserver.c blixscore_io.c
- | strip blixserver
- | o copy the executable blixserver to ~blix/bin/blixserver
- | o make a directory ~blix/scores (owned by user blix, and writable
- | by blix)
- | o adding a line in two files
- | ==> /etc/services
- | blix 8181/tcp # blix highscore server
- | ==> /etc/inetd.conf (or /usr/etc/inetd.conf)
- | blix stream tcp nowait blix /usr/people/blix/bin/blixserver blixserver
- | ^^^^
- | | the user blix has write permission to
- | the directory with the scores.
- |
- | o to get things working do a killall -HUP inetd
- |
- | I have defined BLIXIMAGE to be
- | <img src="http:/www.sgi.com/images/blix.gif">
- | and include a gif image; if you don't want it,
- | simply define BLIXIMAGE as "", otherwise install blix.gif
- | in the approriate directory.
- | This is only used when using html on the 8181 port to see
- | the highscores.
- |
- | See below for the description of the main routine.
- |
- | (c) 1994 Frans van Hoesel, hoesel@chem.rug.nl
- | Xtreme Graphics Software
- */
-
- #define SCOREDIR "/usr/people/blix/scores"
- #define LOGFILE "/usr/people/blix/log"
- #define PASSFILE "/usr/people/blix/password"
- #define BLIXIMAGE "<img src=\"http://www.sgi.com/images/blix.gif\" alt=\"Blix Highscore\" >"
-
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <errno.h>
- #include <malloc.h>
-
- #include "blixscore_io.h"
-
- /* don't define DEBUG in the real production, because the file
- * used for logging doesn't use file locking.
- */
- /*
- * #define DEBUG
- */
-
- #define DEBUG
-
- typedef struct {
- unsigned short imagic;
- unsigned short type;
- unsigned short dim;
- unsigned short xsize;
- unsigned short ysize;
- unsigned short zsize;
- } IMAGE;
- #define IMAGIC 0732
-
- static scorelist_t worldlist;
-
-
- /*__________________________________________________________________
- |
- | main - the tricky part :-)
- |
- | The idea is to maintain one file with all kinds of info, but which
- | has a unique sequence number (worldlist.id); whenever a new
- | highscore is accepted, the id is incremented. The game itself
- | caches all the info on a local disk so there is only some
- | significant network traffic when something changes, which is
- | very unlikely after a while. Also when a user has just installed
- | the game (or otherwise deleted the cached data) some traffic
- | is going on. It is never much data: just the list of scores
- | and the images (which are never larger than 100 x 100).
- | Only the new images that are not in the users cache are send.
- |
- | because the number of requests for the worldlist.id is stored
- | too, the short file with the scores must be rewritten after
- | each request. No big problem.
- | Images are stored in seven separate RGB files, indentified by the sequence
- | number and an extension '.world'. Only the five images with
- | the highest sequence number need to be stored. Normally all the
- | others are removed automatically.
- |
- */
-
-
- #ifdef DEBUG
- FILE *logfile;
- char time_string[30];
-
- void get_time(void) {
- time_t t;
-
- t=time(NULL);
- cftime(time_string, "%D %R ", &t);
- }
- #endif
- #define serverout 1
- #define serverin 0
-
- int main() {
-
- int f = 0;
- char cmd[5];
- char tmpstr[256];
- char passwd[9];
- long your_id;
- long your_score;
- long yoursize;
- long your_addr;
- char your_name[128];
- char your_host[128];
- char *yourimage;
- long imagenum;
- int i;
- int img;
- struct stat buf;
- IMAGE *image;
- char *mark;
- char *full;
-
- # ifdef DEBUG
- logfile = fopen(LOGFILE, "a+");
- get_time();
- # endif
-
- if (read_data(0, cmd, -4) != 4) {
- return -1;
- }
- cmd[4] = '\0';
- # ifdef DEBUG
- fprintf(logfile, "\n%s: %s\n", time_string, cmd);
- # endif
-
-
- if (strcmp(cmd, "GSCR") == 0) {
- /* get score */
- if (read_data(serverin, &your_id, 4) != 4) return -1;
- f = openscore(SCOREDIR "/worldscore", 30);
- if (f == -1) {
- # ifdef DEBUG
- fprintf(logfile, "%s: open local worldscore failed\n", time_string);
- # endif
- return -1;
- }
- readscore(f, &worldlist);
- # ifdef DEBUG
- fprintf(logfile, "%s: your id is %d; my id is %d\n", time_string,
- (int) your_id, (int) worldlist.id);
- # endif
- worldlist.game++;
- writescore(serverout, &worldlist);
- # ifdef DEBUG
- fprintf(logfile, "%s: did send worldscore to you; bye\n", time_string);
- # endif
- lseek(f, 0, SEEK_SET);
- writescore(f, &worldlist);
- close(f);
- return 0;
-
-
-
-
- } else if (strcmp(cmd, "GIMG") == 0) {
- /* get image */
- if (read_data(serverin, &imagenum, 4) != 4) return -1;
- # ifdef DEBUG
- fprintf(logfile, "%s: requested image %d\n",
- time_string, (int)imagenum);
- # endif
- sprintf(tmpstr, SCOREDIR "/%d.world", (int) imagenum);
- img = open(tmpstr, O_RDONLY);
- yoursize = 0;
- if (img >= 0 && fstat(img, &buf) >= 0) {
- yoursize = buf.st_size;
- sprintf(tmpstr,"/%d.world", (int) imagenum);
- writestr(serverout, tmpstr);
- } else {
- writestr(serverout, "");
- }
- write_data(serverout, &yoursize, sizeof(yoursize));
- if (yoursize != 0) {
- yourimage = (char *)malloc(yoursize);
- read_data(img, yourimage, -yoursize);
- if (write_data(serverout, yourimage, -yoursize) != yoursize) {
- # ifdef DEBUG
- fprintf(logfile, "%s: sending image '%s' failed\n",
- time_string, tmpstr);
- # endif
- return -1;
- }
- free(yourimage);
- }
- if (img >= 0) {
- close(img);
- }
- # ifdef DEBUG
- fprintf(logfile, "%s: did send you image %d; bye\n",
- time_string, (int) imagenum);
- # endif
- return 0;
-
-
-
-
- } else if (strcmp(cmd, "PSCR") == 0) {
- /* put score
- * user thinks the highscore is beaten so
- * the score + info + image is being received
- */
- if (read_data(0, &your_score, sizeof(long)) < 0) return -1;
- if (readstr(0, your_name) < 0) return -1;
- your_name[47] = '\0';
- if (readstr(0, your_host) < 0) return -1;
- your_name[47] = '\0';
- if (read_data(0, &your_addr, sizeof(long)) < 0) return -1;
- # ifdef DEBUG
- fprintf(logfile, "%s: your address is %d.%d.%d.%d\n", time_string,
- (int) (your_addr>>24) & 0xff, ((int) your_addr>>16) & 0xff,
- (int) (your_addr>>8) & 0xff, (int) your_addr & 0xff);
- # endif
- if (read_data(0, &yoursize, sizeof(long)) < 0) return -1;
- # ifdef DEBUG
- fprintf(logfile, "%s: your image size is %d\n",
- time_string, (int) yoursize);
- # endif
- if (yoursize != 0) {
- yourimage = (char *)malloc(yoursize);
- if (read_data(0, yourimage, -yoursize) != yoursize) {
- # ifdef DEBUG
- fprintf(logfile, "%s: failed to read image\n", time_string);
- # endif
- return -1;
- }
- }
- /* ok got all the data; now compare it with the
- * data already in the file; and update as needed
- */
- if (your_score % 5 != 0) /* someone cheated */
- return -1;
- f = openscore(SCOREDIR "/worldscore", 30);
- if (f == -1) {
- # ifdef DEBUG
- fprintf(logfile, "%s: failed to open local worldscore\n",
- time_string);
- # endif
- return -1;
- }
- readscore(f, &worldlist);
- if (worldlist.scores[6] >= your_score) {
- # ifdef DEBUG
- fprintf(logfile, "%s: worldscore %d higher than yours\n",
- time_string, (int) worldlist.scores[6]);
- # endif
- return 0;
- }
- /* the high score list records the seven persons
- * with the highest scores, not the seven highest scores.
- * This is to get more variation on your screen:-)
- */
- i = 6;
- for (i=0; i< 6; i++) {
- if (worldlist.addrs[i] == your_addr &&
- strcmp(worldlist.names[i], your_name) == NULL) {
- break;
- }
- }
- while (i > 0 && (worldlist.scores[i-1] < your_score ||
- (worldlist.scores[i] == your_score &&
- (worldlist.addrs[i] != your_addr ||
- strcmp(worldlist.names[i], your_name) != NULL)
- ))) {
- strcpy(worldlist.names[i], worldlist.names[i-1]);
- strcpy(worldlist.hosts[i], worldlist.hosts[i-1]);
- strcpy(worldlist.images[i], worldlist.images[i-1]);
- worldlist.scores[i] = worldlist.scores[i-1];
- worldlist.addrs[i] = worldlist.addrs[i-1];
- i--;
- }
- if (worldlist.scores[i] < your_score ||
- (worldlist.scores[i] == your_score &&
- (worldlist.addrs[i] != your_addr ||
- strcmp(worldlist.names[i], your_name) != NULL)
- )) {
- # ifdef DEBUG
- fprintf(logfile, "%s: you are at place %d with %d points\n",
- time_string, i+1, (int) your_score);
- # endif
- worldlist.id++;
- if (*(worldlist.images[i]) != '\0') {
- unlink(worldlist.images[i]);
- }
- strcpy(worldlist.names[i], your_name);
- strcpy(worldlist.hosts[i], your_host);
- worldlist.scores[i] = your_score;
- worldlist.addrs[i] = your_addr;
- if (yoursize > 0) {
- image = (IMAGE *) yourimage;
- if ( image->imagic != IMAGIC ||
- image->xsize > 100 || image->ysize > 100) {
- /* reject this image */
- *tmpstr = '\0';
- } else {
- sprintf(tmpstr, SCOREDIR "/%d.world", (int) worldlist.id);
- img = open(tmpstr, O_WRONLY | O_CREAT, 0666);
- if (img == -1) {
- # ifdef DEBUG
- fprintf(logfile, "%s: failed to open local image '%s'\n",
- time_string, tmpstr);
- # endif
- *tmpstr = '\0';
- } else {
- write_data(img, yourimage, -yoursize);
- close(img);
- }
- }
- } else {
- *tmpstr = '\0';
- }
- tmpstr[255] = '\0';
- strcpy(worldlist.images[i],tmpstr);
- lseek(f, 0, SEEK_SET);
- writescore(f, &worldlist);
- # ifdef DEBUG
- fprintf(logfile, "%s: did write local worldscore; bye\n",
- time_string);
- # endif
- close(f);
- cleanup_images(&worldlist, SCOREDIR, "world");
- return 1;
- }
- return 0;
-
-
-
- } else if (strcmp(cmd, "RSCR") == 0) {
- /* reset score */
- /* this feature allows the author of the game to reset the
- * score, if he feels it should be, because someone
- * did cheat very badly.
- */
- gets(tmpstr);
- puts("send password:");
- fflush(stdout);
- gets(tmpstr);
- f = open(PASSFILE, O_RDONLY);
- if (f < 0) {
- puts("could not open password file");
- return -1;
- }
- read(f, passwd, 8);
- close(f);
- if (strncmp(passwd, tmpstr, 8) != NULL) {
- puts("reset command refused");
- return -1;
- }
- # ifdef DEBUG
- fprintf(logfile, "%s: accepted reset command\n", time_string);
- # endif
- f = openscore(SCOREDIR "/worldscore", 30);
- readscore(-1, &worldlist);
- worldlist.game = 2;
- worldlist.id = 2;
- writescore(f, &worldlist);
- close(f);
- puts("reset score done; bye");
- return 0;
-
-
- } else if (strncmp(cmd,"GET",3) == 0) {
- /* html request */
- if (fgets(tmpstr, 254, stdin) == NULL) {
- return -1;
- }
- tmpstr[255] = '\0';
- full = strstr(tmpstr, "full");
- mark = strstr(tmpstr, "HTTP/1.0");
- if (mark != NULL) {
- /* this is HTTP/1.0 protocol, so keep reading from the socket
- * until a blank line is found */
- while(fgets(tmpstr, 254, stdin) != NULL && *tmpstr != '\0'
- && *tmpstr != '\n' && *tmpstr != '\r' )
- ; /* do nothing */
- }
- puts("<title>Blix world highscores</title>");
- puts(BLIXIMAGE "<p><br><br>");
- f = openscore(SCOREDIR "/worldscore", 30);
- readscore(f, &worldlist);
- close(f);
- printf("Number of users that played the game: %d\n",
- (int) worldlist.game);
- if (full != NULL)
- printf("<br>Number of updates to this highscore: %d\n",
- (int) worldlist.id);
- puts("<p><br>These are the wizards of blix:<p><dl><dt><dl>");
- for (i=0; i< 7; i++) {
- if (worldlist.names[i] != NULL) {
- printf("<dt><b>%s</b>", worldlist.names[i]);
- if (worldlist.hosts[i] != NULL) {
- printf(" (%s)", worldlist.hosts[i]);
- }
- printf("<dd><b>%d</b> points\n", (int) worldlist.scores[i]);
- if (full != NULL) {
- printf("<br>Address %d.%d.%d.%d\n",
- (int)(worldlist.addrs[i]>>24) & 0xff,
- (int)(worldlist.addrs[i]>>16) & 0xff,
- (int)(worldlist.addrs[i]>>8) & 0xff,
- (int)worldlist.addrs[i] & 0xff);
- if (worldlist.images[i] == NULL ||
- *(worldlist.images[i]) == '\0') {
- printf("<br>no image available\n");
- } else {
- printf("<br>image %s\n",
- strrchr(worldlist.images[i], '/') +1);
- }
- }
- }
- }
- puts("</dl></dl><p><br><i>BLIX </i> is a game written by Frans van Hoesel");
- puts(" for use on fast SGI machines.<p>");
- puts("He can be reached at hoesel@chem.rug.nl<p>");
- puts("Xtreme Graphics Software");
-
-
-
- } else {
- /* rubbish command */
- return -1;
- }
- return 0;
- }
-